package com.bosicloud.cmb.ibp.microplatform.component;

import com.amazonaws.services.cloudformation.model.Output;
import com.bosicloud.cmb.ibp.aws.adapter.api.CloudFormationClient;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.RequestDescribeStackDTO;
import com.bosicloud.cmb.ibp.aws.adapter.commom.model.CFNotifyMessage;
import com.bosicloud.cmb.ibp.commom.dto.exchange.ExchangeMessage;
import com.bosicloud.cmb.ibp.commom.utils.DateUtils;
import com.bosicloud.cmb.ibp.commom.utils.JsonUtil;
import com.bosicloud.cmb.ibp.microplatform.commom.model.IbpCfNotifyMessage;
import com.bosicloud.cmb.ibp.microplatform.commom.model.IbpMspEnvironment;
import com.bosicloud.cmb.ibp.microplatform.commom.model.IbpPlatformInfo;
import com.bosicloud.cmb.ibp.microplatform.dao.IbpCfNotifyMessageMapper;
import com.bosicloud.cmb.ibp.microplatform.dao.IbpMspEnvironmentMapper;
import com.bosicloud.cmb.ibp.microplatform.dao.IbpPlatformInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.bosicloud.cmb.ibp.microplatform.commom.constant.CloudFormationConstant.*;


@Component
@Slf4j
public class MessageExecutor {


    private final IbpCfNotifyMessageMapper notifyMessageMapper;

    private final IbpMspEnvironmentMapper environmentMapper;

    private final CloudFormationClient cloudFormationClient;

    private final IbpPlatformInfoMapper platformInfoMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public MessageExecutor(IbpCfNotifyMessageMapper notifyMessageMapper,
                           IbpMspEnvironmentMapper environmentMapper,
                           CloudFormationClient cloudFormationClient,
                           IbpPlatformInfoMapper platformInfoMapper) {
        this.notifyMessageMapper = notifyMessageMapper;
        this.environmentMapper = environmentMapper;
        this.cloudFormationClient = cloudFormationClient;
        this.platformInfoMapper = platformInfoMapper;
    }


    @Transactional(rollbackFor = Exception.class)
    public void receiveLogic(ExchangeMessage payload) {
        String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-MicroPlatform-Create-CloudFormation Receive Message:{}", toJson);
        CFNotifyMessage message = JsonUtil.parse(toJson, CFNotifyMessage.class);

        IbpCfNotifyMessage ibpCfNotifyMessage = new IbpCfNotifyMessage();
        BeanUtils.copyProperties(message, ibpCfNotifyMessage);
        ibpCfNotifyMessage.setAwsTimestamp(DateUtils.UTCToCST(message.getTimestamp()));
        ibpCfNotifyMessage.setNameSpace(message.getNamespace());
        ibpCfNotifyMessage.setCreateTime(DateUtils.localDateTime2Date());
        int notifyMessageRecord = notifyMessageMapper.insert(ibpCfNotifyMessage);
        log.info("### Save Notify Message insert record:{}", notifyMessageRecord);

        boolean isCreateCloudFormation = Objects.equals(AWS_CLOUD_FORMATION_STACK,
                message.getResourceType().trim());
        if (isCreateCloudFormation) {

            final String clientRequestToken = message.getClientRequestToken();
            final String resourceStatus = message.getResourceStatus();
            log.info("### Get Resource Type:{},ResourceStatus", message.getResourceType(), resourceStatus);
            //更新创建状态
            int updateRecord = environmentMapper.updateMspEnvironment(IbpMspEnvironment.builder()
                    .token(clientRequestToken)
                    .status(resourceStatus)
                    .build());
            log.info("### Update Create status update record:{}", updateRecord);

            //创建完成后获取服务组件URL
            if (Objects.equals(COMPLETE_STATUS, resourceStatus)) {
                savePlatFormInfo(clientRequestToken);
            }
        }


    }

    @Transactional(rollbackFor = Exception.class)
    public void savePlatFormInfo(String clientRequestToken) {

        IbpMspEnvironment mspEnvironment = environmentMapper.selectOne(IbpMspEnvironment
                .builder()
                .token(clientRequestToken)
                .build());
        if (Objects.isNull(mspEnvironment)) {
            return;
        }

        Map<String, String> outPutMap = cloudFormationClient.descirbeStack(RequestDescribeStackDTO
                .builder()
                .accessKey(mspEnvironment.getAccessKey())
                .secretKey(mspEnvironment.getSecretKey())
                .region(mspEnvironment.getRegionName())
                .stackName(mspEnvironment.getStackName())
                .build())
                .stream()
                .collect(Collectors.toMap(Output::getOutputKey, Output::getOutputValue));
        log.info("### Execute SavePlatFormInfo Outputs:{},ResourceStatus", JsonUtil.toJson(outPutMap));

        IbpPlatformInfo build = IbpPlatformInfo
                .builder()
                .ecsClusterName(mspEnvironment.getClusterName())
                .mspEnvironmentId(mspEnvironment.getId())
                .envName(mspEnvironment.getEnvName())
                .createTime(DateUtils.localDateTime2Date())
                .albDns(outPutMap.get(LBS_DNS))
                .zipkinUrl(outPutMap.get(ZIPKIN_SERVER_URL))
                .hystrixUrl(outPutMap.get(HYSTRIX_DASHBOARD_URL))
                .configServerUrl(outPutMap.get(CONFIG_SERVER_URL))
                .eurekaUrl(outPutMap.get(EUREKA_SERVER_URL))
                .albArn(outPutMap.get(ALB_ARN))
                .palbArn(outPutMap.get(PALB_ARN))
                .palb(outPutMap.get(PALB))
                .awsEcsName(outPutMap.get(ECS_NAME))
                .ecsInstanceAsgName(outPutMap.get(ECS_INSTANCE_ASG_NAME))
                .ecsLogGroup(outPutMap.get(ECS_LOG_GROUP))
                .build();
        log.info("### Combined IbpPlatformInfo result:{}", JsonUtil.toJson(build));

        IbpPlatformInfo ibpPlatformInfo = platformInfoMapper.selectOne(IbpPlatformInfo
                .builder()
                .mspEnvironmentId(mspEnvironment.getId())
                .build());
        if (Objects.isNull(ibpPlatformInfo)) {
            int record = platformInfoMapper.insert(build);
            log.info("### Save PlatformInfo record:{}", record);
        } else {
            platformInfoMapper.updatePlatformInfo(build);
            log.info("### UpdatePlatformInfo result:{}", JsonUtil.toJson(build));
        }

    }
}
